<?php

namespace app\common\library;

use alipay\aop\AopClient;
use alipay\aop\request\AlipayTradeAppPayRequest;
use app\common\controller\Api;
use app\common\model\events\Sign;
use app\common\model\MoneyLog;
use app\common\model\order\Goods;
use app\common\model\order\goods\Log;
use app\common\model\order\Order;
use app\common\model\recharge\Order as RechargeOrder;
use app\common\model\User;
use app\common\model\user\Info;
use think\Db;
use think\Env;


/**
 * 统一支付接口
 */
class Pay extends Api
{
    protected $noNeedLogin = ['*'];
    protected $noNeedRight = ['*'];
    protected $config;
    /**
     * 封装统一支付方法
     *
     */
    public static function pay($id, $attach, $userInfo, $pay_type)
    {
        switch ($attach) {
            case 'recharge':
                $order = RechargeOrder::get($id);
                $sn = $order->orderid;
                $order->paytype = $pay_type;

                $money = $order['pay_fee'];
                break;
            case 'order':
                $order = Order::get($id, ['goods']);
                $money = $order['pay_fee'];
                $sn = $order->sn;
                $order->pay_type = $pay_type;
                break;
        }
        $order->examine = null;
        if ($money <= 0) {
            $time = time();
            $order->pay_status = '10';
            $order->order_status = '10';
            $order->paytime = $time;
        } else {
            if ($pay_type == '1') {
                //微信小程序支付
                $jsapi = (new Pay)->minipay($sn, $money, $userInfo->openid, $attach);
                $sdk = [
                    'timeStamp' => (string) $jsapi['timeStamp'],
                    'nonceStr' => $jsapi['nonceStr'],
                    'package' => $jsapi['package'],
                    'signType' => $jsapi['signType'],
                    'paySign' => $jsapi['paySign'],
                ];
            } elseif ($pay_type == '2') {
                //余额支付
                $sdk = Pay::yue($order, '');
            } elseif ($pay_type == '3') {
                //佣金支付
                $sdk = Pay::commission_pay($order);
            } elseif ($pay_type == '4') {
                //线下支付
                $sdk = Pay::offline_pay($order);
                $order->examine = 10;
            }
        }
        $order->allowField(true)->save();
        return $sdk ?? '';
    }


    /**
     * 余额支付
     *
     */
    private static function yue($data, $payPwd = '')
    {

        $user = User::get($data['user_id']);

        // if ($user->pay_pwd != md5(md5($payPwd) . 'pcy')) {
        //     exception('支付密码不正确');
        // }

        if ($data['pay_fee'] > $user->money) {
            exception('余额不足');
        }

        Db::startTrans();
        try {
            if ($data['pay_fee'] > 0) {
                MoneyLog::income($user->id, $data['pay_fee'], 2, 500, $data['sn']);
            }
            self::orderFulfillment($data);
            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();

            exception($e->getMessage());
        }
        return true;
    }
    /**
     * 佣金支付
     *
     */
    private static function commission_pay($data)
    {

        $user = User::get($data['user_id']);

        if ($data['pay_fee'] > $user->commission) {
            exception('佣金不足');
        }
        Db::startTrans();
        try {
            if ($data['pay_fee'] > 0) {
                MoneyLog::income($user->id, $data['pay_fee'], 2, 301, $data['sn']);
            }
            self::orderFulfillment($data);
            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();

            exception($e->getMessage());
        }
        return true;
    }
    /**
     * 线下支付
     *
     */
    private static function offline_pay($data)
    {

        Db::startTrans();
        try {
            self::orderFulfillment($data);
            Db::commit();
        } catch (\Exception $e) {
            Db::rollback();
            exception($e->getMessage());
        }
        return true;
    }
    /**
     * 支付宝支付
     *
     */
    private static function alipay($data)
    {
        if (Env::get('app.debug') == true) {
            $data['pay_money'] = 0.01;
        }
        $aop = new AopClient();
        $object['out_trade_no'] = $data['sn'];
        $object['total_amount'] = $data['pay_money'];
        $object['subject'] = '订单支付';
        $json = json_encode($object);
        $request = new AlipayTradeAppPayRequest();
        $request->setNotifyUrl(cdnurl('/api/notify/alipayNotify', true));
        $request->setBizContent($json);
        $result = $aop->sdkExecute($request);
        return $result;
    }

    //小程序下单
    public static function minipay($sn, $pay_fee, $openid, $attach = 'order')
    {
        $out_trade_no = $sn;
        $money = $pay_fee;
        if (empty($out_trade_no)) {
            exception('缺少参数order_sn');
        }
        // 官方提供网址
        $url = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi";
        $urlarr = parse_url($url); //拆解为：[scheme=>https,host=>api.mch.weixin.qq.com,path=>/v3/pay/transactions/native]
        $time = time(); //时间戳
        $noncestr = self::getNonceStr();
        $appid = Env::get('wechat.min_app_id'); //appID
        $mchid = Env::get('wechat.mchid'); //商户ID
        $xlid = Env::get('wechat.xlid'); //证书序列号
        $data = array();
        $data['appid'] = $appid;
        $data['mchid'] = $mchid;
        $data['attach'] = $attach;
        $data['description'] = '商品描述'; //商品描述
        $data['out_trade_no'] = $out_trade_no; //订单编号，订单号在微信支付里是唯一的
        $data['notify_url'] = cdnurl('/api/notify/wechatNotify', true); //需根据自己的情况修改回调接口，也可以为空
        $data['amount']['total'] = $money * 100; //金额 单位 分
        $data['scene_info']['payer_client_ip'] = $_SERVER["REMOTE_ADDR"];; //场景ip
        $data['payer']['openid'] = $openid; //openid
        $array = json_encode($data, JSON_UNESCAPED_UNICODE);
        //签名，包含了$data数据、微信指定地址、随机数和时间
        $key = self::getSign($array, $urlarr['path'], $noncestr, $time);
        $token = sprintf('mchid="%s",serial_no="%s",nonce_str="%s",timestamp="%d",signature="%s"', $mchid, $xlid, $noncestr, $time, $key);
        //头部信息
        $header = array(
            'Accept: application/json',
            'Content-Type: application/json',
            'User-Agent:*/*',
            'Authorization: WECHATPAY2-SHA256-RSA2048 ' . $token
        );
        $res = self::curl_post_https($url, $array, $header);
        $prepay_id = json_decode($res, true)['prepay_id'];
        $paySign = self::getWechartSign($appid, $time, $noncestr, 'prepay_id=' . $prepay_id);
        $payData = [
            'timeStamp' => (string) $time,
            'nonceStr' => $noncestr,
            'package' => 'prepay_id=' . $prepay_id,
            'signType' => 'RSA',
            'paySign' => $paySign
        ];
        return $payData;
    }
    // php -f D:\phpstudy_pro\WWW\1255\vendor\wechatpay\wechatpay\bin\CertificateDownloader.php -- -k QbyyrkXYWbwSVT3kw3FwBj1xv9b8rLLu -m 1586569011 -f C:\Users\Administrator\Desktop\1586569011_20230628_cert\apiclient_key.pem -s 63005C1EB8FE15AF1EA278F9C3F774D168929FCD -o C:\Users\Administrator\Desktop\1586569011_20230628_cert\
    // 0 1 * * *  /usr/bin/php /www/wwwroot/1214test.ciyuantiaoyue.com/1214-3.0/public/index.php /addons/crontab/autotask/index
    //微信app支付
    private static function wxpay($order, $attach)
    {
        $out_trade_no = $order['sn'];
        $money = $order['pay_money'];
        if (Env::get('app.debug') == true) {
            $money = 0.01;
        }
        if (empty($out_trade_no)) {
            exception('缺少参数order_sn');
        }
        // 官方提供网址
        $url = "https://api.mch.weixin.qq.com/v3/pay/transactions/app";
        $urlarr = parse_url($url); //拆解为：[scheme=>https,host=>api.mch.weixin.qq.com,path=>/v3/pay/transactions/native]
        $time = time(); //时间戳
        $noncestr = self::getNonceStr();
        $appid = config('site.app_id'); //appID
        $mchid = config('site.mch_id'); //商户ID
        $xlid = config('site.serial_no'); //证书序列号
        $data = array();
        $data['appid'] = $appid;
        $data['mchid'] = $mchid;
        $data['attach'] = $attach;
        $data['description'] = '商品描述'; //商品描述
        $data['out_trade_no'] = $out_trade_no; //订单编号，订单号在微信支付里是唯一的
        $data['notify_url'] = cdnurl('/api/notify/wechatNotify', true); //需根据自己的情况修改回调接口，也可以为空
        $data['amount']['total'] = $money * 100; //金额 单位 分
        $data['scene_info']['payer_client_ip'] = $_SERVER["REMOTE_ADDR"];; //场景ip
        // $data['payer']['openid'] = $openid; //app支付不需要openid
        $data = json_encode($data);

        //签名，包含了$data数据、微信指定地址、随机数和时间
        $key = self::getSign($data, $urlarr['path'], $noncestr, $time);
        $token = sprintf('mchid="%s",serial_no="%s",nonce_str="%s",timestamp="%d",signature="%s"', $mchid, $xlid, $noncestr, $time, $key);
        //头部信息
        $header = array(
            'Accept: application/json',
            'Content-Type: application/json',
            'User-Agent:*/*',
            'Authorization: WECHATPAY2-SHA256-RSA2048 ' . $token
        );
        //向微信接口地址提交json格式的$data和header的头部信息，得到返回值
        $res = self::curl_post_https($url, $data, $header);
        $prepay_id = json_decode($res, true)['prepay_id'];


        $paySign = self::getWechartSign($appid, $time, $noncestr, $prepay_id);
        $payData = [
            'appid' => $appid,
            'partnerid' => $mchid,
            'prepayid' => $prepay_id,
            'package' => "Sign=WXPay",
            'noncestr' => $noncestr,
            'timestamp' => (string) $time,
            'sign' => $paySign
        ];
        return $payData;
    }
    //充值支付成功
    public static function rechargeFulfillment($sn, $transaction_id = null)
    {
        $time = time();
        try {
            $order = RechargeOrder::get(['orderid' => $sn, 'pay_status' => '0']);
            if ($order) {
                $order->pay_status = '10';
                $order->paytime = $time;
                $order->transaction_id = $transaction_id;
                $order->save();
                MoneyLog::income($order->user_id, bcadd($order->pay_fee, $order->send_fee, 2), 1, 501, $order->orderid);
            }
        } catch (\Exception $e) {
            exception($e->getMessage());
        }
    }
    //订单支付成功
    public static function orderFulfillment($order, $transaction_id = null)
    {
        $time = time();
        try {
            if ($order) {
                if ($order->order_status == '0') {
                    $order->order_status = '10';
                    $order->transaction_id = $transaction_id;
                    if ($order->pay_type != '4') {
                        $order->paytime = $time;
                        if ($order->order_type == '2') {
                            $expiration_date = config('site.expiration_date');
                            $goods = $order->goods;
                            $arr = [
                                'user_id' => $order->user_id,
                                'group_id' => 2,
                                'province' => $order->province,
                                'city' => $order->city,
                                'area' => $order->area,
                                'address' => $order->regio,
                                'content' => json_encode($order),
                                'first_cate' => $goods[0]['first_cate'],
                                'two_cate' => $goods[0]['two_cate'],
                                'region_id' => $goods[0]['region_id'],
                                'expirationtime' => strtotime("+" . $expiration_date . " day"),
                            ];
                            if ($order->renewal == 1) {
                                $expiration = $expiration_date * 86400;
                                $data = Info::get(['first_cate' => $goods[0]['first_cate'], 'two_cate' => $goods[0]['two_cate'], 'address' => $order->regio, 'user_id' => $order->user_id]);
                                if ($data) {
                                    $data->expirationtime = bcadd($data->expirationtime ?? $time, $expiration, 0);
                                    $data->save();
                                } else {
                                    Info::create($arr, true);
                                }
                            } else {
                                Info::create($arr, true);
                            }
                            User::where('id', $order->user_id)->update(['group_id' => 2]);
                        }
                        //订单支付成功，冻结金额日志
                        MoneyLog::frozenlog_commission($order);
                        Log::add_performance_detail($order, $time);
                    }
                    $order->save();
                }
            }
        } catch (\Exception $e) {
            exception($e->getMessage());
        }
    }

    //获取随机字符串
    public static function getNonceStr()
    {
        $strs = "QWERTYUIOPASDFGHJKLZXCVBNM1234567890";
        $name = substr(str_shuffle($strs), mt_rand(0, strlen($strs) - 11), 32);
        return $name;
    }

    //微信支付签名
    public static function getSign($data, $url, $randstr, $time)
    {
        $str = "POST" . "\n" . $url . "\n" . $time . "\n" . $randstr . "\n" . $data . "\n";
        $key = file_get_contents(ROOT_PATH . str_replace('/', DS, substr('/application/certs/apiclient_key.pem', 1))); //在商户平台下载的秘钥,读取到变量
        $str = self::getSha256WithRSA($str, $key);
        return $str;
    }

    //调起支付的签名
    public static function getWechartSign($appid, $timeStamp, $noncestr, $prepay_id)
    {
        $str = $appid . "\n" . $timeStamp . "\n" . $noncestr . "\n" . $prepay_id . "\n";
        $key = file_get_contents(ROOT_PATH . str_replace('/', DS, substr('/application/certs/apiclient_key.pem', 1))); //在商户平台下载的秘钥,读取到变量
        $str = self::getSha256WithRSA($str, $key);
        return $str;
    }

    //加密
    public static function getSha256WithRSA($content, $privateKey)
    {
        $binary_signature = "";
        $algo = "SHA256";
        openssl_sign($content, $binary_signature, $privateKey, $algo);
        $sign = base64_encode($binary_signature);
        return $sign;
    }

    /* PHP CURL HTTPS POST */
    public static function curl_post_https($url, $data, $header)
    { // 模拟提交数据函数
        $curl = curl_init(); // 启动一个CURL会话
        curl_setopt($curl, CURLOPT_URL, $url); // 要访问的地址
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0); // 对认证证书来源的检查
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0); // 从证书中检查SSL加密算法是否存在，如果出错则修改为0，默认为1
        curl_setopt($curl, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); // 模拟用户使用的浏览器
        curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); // 使用自动跳转
        curl_setopt($curl, CURLOPT_AUTOREFERER, 1); // 自动设置Referer
        curl_setopt($curl, CURLOPT_POST, 1); // 发送一个常规的Post请求
        curl_setopt($curl, CURLOPT_POSTFIELDS, $data); // Post提交的数据包
        curl_setopt($curl, CURLOPT_TIMEOUT, 30); // 设置超时限制防止死循环
        curl_setopt($curl, CURLOPT_HEADER, 0); // 显示返回的Header区域内容
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // 获取的信息以文件流的形式返回
        curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
        $tmpInfo = curl_exec($curl); // 执行操作
        if (curl_errno($curl)) {
            echo 'Errno' . curl_error($curl); //捕抓异常
        }
        curl_close($curl); // 关闭CURL会话
        return $tmpInfo; // 返回数据，json格式
    }
}
